#pragma once
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>
#include <memory>
// #define Child_process_num 5 // 子进程数量
using callback_t = std::function<void(int fd)>;

// 定义一个信道
class Channel
{
private:
    int _wfd; // 文件描述符
    std::string _name; // 信道的名字
    pid_t _sub_target; // 目标进程的pid
    /* data */
public:
    Channel(/* args */);
    Channel(int wfd,  const std::string name, pid_t id)
        : _wfd(wfd), _name(name), _sub_target(id) {}
    ~Channel();
    // int getsfd(){
    //     return _sfd;
    // }
    // getname
    std::string getname()
    {
        return _name;
    }
    // 获得信道的文件描述符
    int getfd()
    {
        return _wfd;
    }
    pid_t getpid()
    {
        return _sub_target;
    }
    // 信道打印
    void Print()
    {
        std::string ch = "文件描述符：" + std::to_string(_wfd) + ";" + _name + "_sub_target:" + std::to_string(_sub_target);
        std::cout << ch << std::endl;
    }
    void Close() // 关闭写端
    {
        close(_wfd);
    }
    void WaitProcess()
    {
        pid_t rid = waitpid(_sub_target, NULL, 0);
        if (rid == -1)
        {
            perror("Waitpid 失败 ！");
        }
        else if(rid > 0){
            std::cout<<"子进程："<<rid<<"回收成功"<<std::endl;
        }
        else if(rid == 0){
            std::cout<<"子进程未退"<<std::endl;
        }
    }
};
Channel::~Channel()
{
}
Channel::Channel()
{
}

// 进程池类
class MyProcessPool
{
private:
    // 1.建立存放所有的信道
    std::vector<Channel> Channels;
    int _num = 5;
    /* data */
public:
    // 初始化进程池
    bool InitProcessPool(callback_t cb)
    {
        //创建一个管道及对应一个子进程，一个写端的文件描述符+一个管道，加一个读端的
        for (int i = 0; i < _num; i++)
        {
            // 创建管道
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if (n < 0)
                return false;
            // 创建子进程
            
            int id = fork();
            if (id < 0)
                return false;
            else if (id == 0)
            {
                // 创建成功，子进程
                close(pipefd[1]); // 关写
                // 子进程进行回调
                cb(pipefd[0]);
               
                exit(1);
            }
            // 父进程
            close(pipefd[0]); // 关读
            std::string name = "信道—>" + std::to_string(i) + ";";
            // 将所有的信道存在一个vector里，方便父进程控制子进程
            Channel channel(pipefd[1], name, id);
            Channels.push_back(channel);
            // 另外一种写法
            // Channels.emplace_back(pipefd[1],name,id);
            // sleep(1);
        }

        return true;
    }
    // 3.唤醒子进程，让子进程完成任务
    // 3.1选择一个信道，负载均衡
    void ControlProcess(int n = 10) // 控制子进程
    {
        int index = 0;
        while (n)
        {
            int who = index;
            index++;
            index %= Channels.size();
            int num = 1;
            std::cout << "父进程选的信道是" << Channels[who].getname() << "信道写入文件描述符：" <<Channels[who].getfd() <<"目标进程id:" + std::to_string(Channels[who].getpid()) + "目标进程文件描述符:" << std::endl;
            std::cout << "task_num = " << n--<<std::endl;
            // 往一个信道中写入一个int类型
            write(Channels[who].getfd(), &num, sizeof(num)); //
            sleep(1);
        }
    }

    // //对Channels做测试
    // for(auto& ch:Channels){
    //     ch.Print();
    //     sleep(1);
    // }

    MyProcessPool(const int &num) : _num(num) {}
    ~MyProcessPool();

    // 等待子进程
    void WaitChildProcess()
    {
        // // 关闭写端，子进程就会退出，就需要父进程回收子进程
        // for (auto &c : Channels)
        // {
        //     c.Close();
        // }
        // 从后往前关
        for (int i = Channels.size()-1; i >= 0; i--)
        {
            Channels[i].Close();
            std::cout<<"子进程："<<Channels[i].getpid()<<"退出"<<std::endl;
            Channels[i].WaitProcess();

        }
    }
};
MyProcessPool::~MyProcessPool(/* args */)
{
}
